<?php
namespace Martdb\Utils;

use Martdb\Exceptions\TIllegalArgumentException;

/**
 * Map类型
 *
 * @author Chunlin Jing
 */
class TMap
{
    // size, isEmpty, keySet, values, entrySet,
    // get, put, putAll, remove, clear,
    // containsKey, containsValue, ...
    
    // The table, initialized on first use, and resized as necessary.
    private $table = array();
    
    // The number of key-value mappings contained in this map.
    private $size = 0;
    
    // Returns the number of key-value mappings in this map.
    public function size() {
        return $this->size;
    }
    
    // Returns <tt>true</tt> if this map contains no key-value mappings.
    public function isEmpty() {
        return $this->size == 0;
    }
    
    // Returns a {@link Set} view of the keys contained in this map.
    public function keySet() {
        return array_keys($this->table);
    }
    
    // This implementation returns a collection that values.
    public function values() {
        return array_values($this->table);
    }
    
    // Returns a {@link Set} view of the mappings contained in this map.
    public function entrySet() {
        $es = array();
        foreach ($this->table as $key => $value) {
            $es[$key] = $value;
        }
        return $es;
    }
    
    // Returns the value to which the specified key is mapped,
    // or {@code null} if this map contains no mapping for the key.
    public function get($key) {
        return $this->table[$key];
    }
    
    // Associates the specified value with the specified key in this map.
    // If the map previously contained a mapping for the key, the old value is replaced.
    public function put($key, $value) {
        if (is_null($key)) {
            throw new TIllegalArgumentException("Key cant not be null");
        }
        $oldValue = null;
        if (array_key_exists($key, $this->table)) {
            $oldValue = $this->table[$key];
        } else {
            $this->size++;
        }
        $this->table[$key] = $value;
        return $oldValue;
    }
    
    // Copies all of the mappings from the specified map to this map.
    public function putAll($m) {
        if (is_null($m) || !($m instanceof TMap)) {
            throw new TIllegalArgumentException("Parameter must be Map");
        }
        foreach ($m->table as $key => $value) {
            $this->table[$key] = $value;
        }
        $this->size = count($this->table);
    }
    
    // Removes the mapping for the specified key from this map if present.
    public function remove($key) {
        $oldValue = null;
        if (array_key_exists($key, $this->table)) {
            $oldValue = $this->table[$key];
            unset($this->table[$key]);
            $this->size--;
        }
        return $oldValue;
    }
    
    // Removes all of the mappings from this map.
    // The map will be empty after this call returns.
    public function clear() {
        $this->table = array();
        $this->size = 0;
    }
    
    // Returns <tt>true</tt> if this map contains a mapping for the specified key.
    public function containsKey($key) {
        // Warning: array_key_exists(): The first argument should be either a string or an integer
        return array_key_exists($key, $this->table);
    }
    
    // Returns <tt>true</tt> if this map maps one or more keys to the specified value.
    public function containsValue($value) {
        $key = array_search($value, $this->table, true);
        return is_null($key);
    }
    
    // Override
    public function __toString() {
        $str = "{";
        if ($this->size == 0) {
            return $str."}";
        }
        foreach ($this->table as $key => $value) {
            $value = is_bool($value) ? ($value ? "true" : "false") : $value;
            $str .= $key."=".$value.", ";
        }
        $str = rtrim($str, ", ");
        return $str."}";
    }
}

